import { Col } from "./data_ext";
import { GameConfig } from "./game_config";
import { LibraryRecord, Library } from "./library";
import { BundleInfo } from "./loader";
import Macro from "./macro";
import SerializeAble, { Serialize, SerializeClass } from "./serialize";
import { Subject } from "./subject";

export const NATIVE_PATHS = {
    CACHE_DATA: "CacheData", //CacheData 文件
    DIR_SCREEN_SHOTS: "ScreenShots" //ScreenShots 文件夹
};

@SerializeClass("CacheRecord")
export class CacheRecord<T> extends SerializeAble {
    subject: Subject = new Subject();

    @Serialize()
    timestamp: number = 0;
    @Serialize()
    timeDuring: number = 0;
    @Serialize()
    version = "";
    @Serialize()
    data: T;

    static Create<T>(data: T, version: string = Macro.APP_VERSION) {
        let rec = new CacheRecord<T>();
        rec.data = data;
        rec.timestamp = Date.now();
        rec.version = version;
        return rec;
    }

    static CheckTime<T>(rec: CacheRecord<T>) {
        return Date.now() - rec.timestamp < rec.timeDuring;
    }
    static CheckVersion<T>(rec: CacheRecord<T>, version: string) {
        return version === rec.version;
    }
};

@SerializeClass("CacheRecordCollection")
export class CacheRecordCollection extends SerializeAble {
    @Serialize()
    col: Col<CacheRecord<any>> = {};
    get<T>(key: string) {
        let rec: CacheRecord<T> = null;
        rec = this.col[key];
        if (!rec || !CacheRecord.CheckVersion(rec, data.gameConfig.version)) {
            return undefined;
        }
        return rec.data;
    }
    set<T>(key: string, val: T) {
        let rec: CacheRecord<T> = this.rec(key, val);
        rec.data = val;
        data.save();
        return rec.data;
    }
    rec<T>(key: string, defVal: T) {
        let rec: CacheRecord<T> = null;
        rec = this.col[key];
        if (!rec || !CacheRecord.CheckVersion(rec, data.gameConfig.version)) {
            rec = CacheRecord.Create<T>(defVal, data.gameConfig.version);
            this.col[key] = rec;
        }
        return rec;
    }
    del(key: string) {
        if (this.col[key]) {
            this.col[key] = null;
            delete this.col[key];
            data.save();
        }
    }
};

export class CacheData extends SerializeAble {
    //bundle 载入的LOG 名字-版本-来源(origin,local)
    // bundleVersionStatus: string[] = [];
    bundleInfos: BundleInfo[] = [];
    gameConfig: GameConfig = null;

    protected _librarys: Map<any, any> = new Map();

    getLibrary<T extends LibraryRecord>(type: { new(): T }) {
        return <Library<T>>this._librarys.get(type);
    }
    setLibrary<T extends LibraryRecord>(type: { new(): T }, group: string) {
        let lib = new Library<T>(group);
        lib.init();
        this._librarys.set(type, lib);
    }
    hasLibrary<T extends LibraryRecord>(type: { new(): T }) {
        return this._librarys.has(type);
    }

    //临时
    cache: CacheRecordCollection = new CacheRecordCollection();
    //storage
    @Serialize(CacheRecordCollection)
    storage: CacheRecordCollection = new CacheRecordCollection();

    get FramePath() {
        return window["FramePath"];
    }
    get BundlePath() {
        return window["BundlePath"];
    }
    get GamePath() {
        return window["GamePath"];
    }

    load() {
        try {
            let jsonStr = "";
            if (cc.sys.isNative) {
                let writePath = jsb.fileUtils.getWritablePath();
                jsonStr = jsb.fileUtils.getStringFromFile(`${writePath}/${NATIVE_PATHS.CACHE_DATA}`);
            }
            else {
                jsonStr = cc.sys.localStorage.getItem(`${data.gameConfig.key}/${NATIVE_PATHS.CACHE_DATA}`);
            }
            if (jsonStr) {
                this.assignFromJSON(jsonStr);
            }
        }
        catch (e) {
            console.error("CacheData::load, error:", e);
        }
    }
    save() {
        try {
            let jsonStr = JSON.stringify(this);
            if (cc.sys.isNative) {
                let writePath = jsb.fileUtils.getWritablePath();
                jsb.fileUtils.writeStringToFile(jsonStr, `${writePath}/${NATIVE_PATHS.CACHE_DATA}`);
            }
            else {
                cc.sys.localStorage.setItem(`${data.gameConfig.key}/${NATIVE_PATHS.CACHE_DATA}`, jsonStr);
            }
        } catch (e) {
            console.error("CacheData::save, error:", e);
        }
    }
};

var data = new CacheData();
export default data;

window["cdata"] = data;